#include <linux/module.h>
#include <linux/init.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "i2c_ap3216c.h"
#define DEV_NAME   "ap3216c"
struct ap3216c_dev_st
{
    dev_t dev_num;          //设备号
    struct cdev cdev_ap3216c;   //字符设备结构体
    struct class *class;    //所属的类
    struct device *device;  //设备结构体
    struct device_node *nd; //设备树节点
    int major;              //主设备号
    int minor;              //次设备号
    struct i2c_client *client;//设备树i2c节点

};
static struct ap3216c_dev_st ap3216c_dev;
static int ap3216c_read_regs(struct ap3216c_dev_st *p_ap3216cdev,unsigned char reg,unsigned char* buf)
{
    struct i2c_msg msg[2];
    struct i2c_client *client=p_ap3216cdev->client;
    unsigned char wdata=reg;
    //write
    msg[0].buf=&wdata;
    msg[0].addr=client->addr;
    msg[0].flags=0;
    msg[0].len=1;
    //read
    msg[1].buf=buf;
    msg[1].addr=client->addr;
    msg[1].flags=I2C_M_RD;
    msg[1].len=1;
    return i2c_transfer(p_ap3216cdev->client->adapter,msg,2);
}
static int ap3216c_write_regs(struct ap3216c_dev_st *p_ap3216cdev,unsigned char reg,char* buf,int len)
{
    struct i2c_msg msg;
    struct i2c_client *client=p_ap3216cdev->client;
    //address + data
    unsigned char wdata[2];
    wdata[0]=reg;
    memcpy(&wdata[1],buf,len);
    msg.buf=wdata;
    msg.addr=client->addr;
    msg.flags=0;
    msg.len=len+1;
    return i2c_transfer(p_ap3216cdev->client->adapter,&msg,1);
}
static int ap3216c_init(struct ap3216c_dev_st *p_ap3216cdev)
{
    int ret=0;
    char data=0x04;
    ret = ap3216c_write_regs(p_ap3216cdev, AP3216C_SYSTEMCONG, &data,1);
    mdelay(50);
    data=0x03;
    ret += ap3216c_write_regs(p_ap3216cdev, AP3216C_SYSTEMCONG, &data,1);
    if (ret == 2)
        return 0;
    else
        return -1;
}

int ap3216c_open(struct inode *id, struct file *filp)
{
    /* 文件描述符对应的内核中的file */
    filp->private_data=&ap3216c_dev;
    return ap3216c_init(&ap3216c_dev);
}
ssize_t ap3216c_read(struct file *filp, char __user *buf, size_t size, loff_t * off_t)
{
    struct ap3216c_dev_st *p_dev=filp->private_data;
    unsigned char raw_data[6]={0};
    unsigned short data[3]={0};
    int i;
    for(i=0;i<6;i++)
        ap3216c_read_regs(p_dev,AP3216C_IRDATALOW+i,&raw_data[i]);
    //检查数据是否合法
    //ir data
    if(raw_data[0]&(1<<7))
    {
        data[0]=0;
    }
    else
    {
        //dddd dddd ？### ##dd 
        //d:data bit,#:not data,?:if data valid
        data[0]=(raw_data[1]*(1<<2))+(raw_data[0]&(0x03));
    }
    //als data
    data[1]=raw_data[3]*(1<<8)+raw_data[2];
    //ps data
    if(raw_data[4]&(1<<6)||raw_data[5]&(1<<6))
    {
        data[2]=0;
    }
    else
    {
        //#?dd dddd #?## dddd 
        //d:data bit,#:not data,?:if data valid
        data[2]=((raw_data[5]&(0x3F))*(1<<4))+(raw_data[4]&(0x0F));
    }
    if(!copy_to_user(buf,data,sizeof(data)))
        return sizeof(data);//success
    else
        return 0;//error
}

int ap3216c_release(struct inode *node, struct file *filp)
{
    return 0;
}
static struct file_operations ap3216c_fops=
{
    .owner=THIS_MODULE,
    .open=ap3216c_open,
    .read=ap3216c_read,
    .release=ap3216c_release,
};
static int ap3216c_probe(struct i2c_client *client,const struct i2c_device_id* ap3216c_id)
{
    //请求设备号
    alloc_chrdev_region(&ap3216c_dev.dev_num,0,1,DEV_NAME); 
    //初始化cdev
    ap3216c_dev.cdev_ap3216c.owner=THIS_MODULE;
    cdev_init(&ap3216c_dev.cdev_ap3216c,&ap3216c_fops);
    //cdev添加到系统
    cdev_add(&ap3216c_dev.cdev_ap3216c,ap3216c_dev.dev_num,1);
    //创建类    
    ap3216c_dev.class=class_create(THIS_MODULE,DEV_NAME);
    if(IS_ERR(ap3216c_dev.class))
        return PTR_ERR(ap3216c_dev.class);
    //创建设备
    ap3216c_dev.device=device_create(ap3216c_dev.class,NULL,ap3216c_dev.dev_num,NULL,DEV_NAME);
    if(IS_ERR(ap3216c_dev.device))
        return PTR_ERR(ap3216c_dev.device);
    ap3216c_dev.client=client;
    printk("probe OK\n");
    return 0;
}
static int ap3216c_remove(struct i2c_client *client)
{
    cdev_del(&ap3216c_dev.cdev_ap3216c);
    unregister_chrdev_region(ap3216c_dev.dev_num,1);
    device_destroy(ap3216c_dev.class,ap3216c_dev.dev_num);
    class_destroy(ap3216c_dev.class);
    return 0;
}
/*设备树匹配*/
static const struct of_device_id ap3216c_ids[] = {
    { .compatible = "steve,ap3216c" },
    {},
};
/*传统匹配*/
const struct i2c_device_id ap3216c_id_table[]={
    {.name="steve,ap3216c"},
    {},
};
static struct i2c_driver ap3216c_driver={
    .driver={
        .name="ap3216c",
        .owner =	THIS_MODULE,
        .of_match_table = of_match_ptr(ap3216c_ids),
    },
    .id_table=ap3216c_id_table,
    .probe=ap3216c_probe,
    .remove=ap3216c_remove,
};
module_i2c_driver(ap3216c_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("steve");